package Cluedo.GUI2;

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.Hashtable;
import java.util.StringTokenizer;
import java.util.Vector;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.border.Border;

import Cluedo.AI.ComplexAI;
import Cluedo.AI.SimpleAI;
import Cluedo.AI.SmartSimpleAI;
import Cluedo.API.CluedoConfig;
import Cluedo.API.Constants;
import Cluedo.API.LanguagePack;
import Cluedo.API.Resources;
import Cluedo.API.SoundEngine;
import Cluedo.Controller.GameController;
import Cluedo.Game.Player;

/**
 * GameMenu should be point of entry and provides a start screen with options for.. <p>
 * <li> - New Game
 * <li> - Load Game 
 * <li> - Help
 * <li> - etc 
 * 
 * @author Alex Ellis
 *
 */
public class GameMenu extends JFrame implements ActionListener {
	/** Pointer to the GUI being created */
	AdvanceGUI guiPointer = null;
	
	/** Pointer to the gameController to be used in this game */
	GameController gameController = null;

	/**
	 * Group for language pack
	 */
	static String langGroup = "game_menu";
	
	/**
	 * Saved properties such as whether to use sound or UI decoration.
	 * 
	 */
	static Hashtable properties = new Hashtable();

	/**
	 * Sound on?
	 */
	static boolean soundEnabled = true;
	
	/**
	 * Quickly loads in a couple of user preferences.
	 *
	 */
	public static void getConfig() {
	    StringTokenizer lines =null;
	    try {
	        lines = new StringTokenizer ( Resources.catTextFileExt(Constants.DEFAULT_CONFIG_FILE, null), "\n");
	    }
	    catch(Exception e) {
	        return;
	    }
	    String parts[]; 
	    while(lines.hasMoreElements() == true) {
	        parts = ((String) lines.nextElement()).split("=");
	        
	        if(parts.length == 2 && !parts[0].startsWith("#")) {
	            properties.put(parts[0].trim(), (parts[1].trim().equals("true") || parts[1].trim().equals("false"))  ? (parts[1].trim().equals("true") ? "true" :"false" ) : parts[1] );
	        }
	        
	    }
	    
	}


    /**
	 * New GameMenu screen 
	 * @param args Title of JFrame
	 */
	public GameMenu(String args) {
		super(args);
		LanguagePack.initaliseLanguage("en-gb");
		
		Container content = getContentPane();
		setSize(400, 500);
		content.setLayout(new BorderLayout());

		JPanel startButtons = new JPanel();
		startButtons.setLayout(new GridLayout(5,1));
		
		JPanel left = new JPanel();
		JPanel right = new JPanel();
		JPanel top = new JPanel();
		top.setLayout(new BorderLayout());

		JLabel caption = new JLabel(LanguagePack.getString("game_slogan", "cluedo"));
		caption.setHorizontalAlignment(SwingConstants.CENTER);
		
		caption.setFont(new Font("Tahoma", Font.BOLD,  18));

		ImageIcon bg_icon = createImageIcon(Constants.DEFAULT_SPLASH_IMAGE, "welcome");

		top.add(new JLabel(bg_icon), BorderLayout.NORTH);
		top.add(caption, BorderLayout.SOUTH);
				
		setResizable(false);
		JButton buttons[] = new JButton[5];

		buttons[0] = makeButton("new_game", LanguagePack.getString("new_game", langGroup));
		buttons[1] = makeButton("load_game", LanguagePack.getString("load_game", langGroup));
		buttons[2] = makeButton("options", LanguagePack.getString("options", langGroup));
		buttons[3] = makeButton("open_help", LanguagePack.getString("open_help", langGroup));
		buttons[4] = makeButton("quit", LanguagePack.getString("quit", langGroup));

		Box buttonBox = Box.createVerticalBox();
		
		for(int i = 0; i < buttons.length; i++) {
			buttons[i].addActionListener(this);
			
			Box row = Box.createHorizontalBox();
			
			buttons[i].setMaximumSize(new Dimension(200, 30));
			row.add(buttons[i]);

			row.add( Box.createVerticalGlue() );
			
			buttonBox.add(row);
		}
	
   		Border border = BorderFactory.createEtchedBorder();
		JPanel buttonMenu = new JPanel();
		buttonBox.setBorder(border);

		buttonMenu.setLayout(new BorderLayout());

		buttonMenu.add(buttonBox, BorderLayout.CENTER);

		content.add(top, BorderLayout.NORTH);
		content.add(left, BorderLayout.WEST);
		content.add(right, BorderLayout.EAST);
		content.add(buttonMenu, BorderLayout.CENTER);
		
		
		centre();
		
	    SoundEngine soundEngine = new SoundEngine();
		soundEngine.start();
		// TODO: add this sound line back
		SoundEngine.bufferSound(Constants.WELCOME_SOUND);
	
        setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
        
	}
	
	/**
	 * @param function
	 * @param caption
	 * @return matching button
	 */
	private static JButton makeButton(String function, String caption) {
		JButton button = new JButton(caption);
		button.setActionCommand(function);
		return button;
	}

	public void actionPerformed(ActionEvent e) {
		if(e.getActionCommand().equals("quit")) {
			int selectedValue = JOptionPane.showConfirmDialog(null,
				LanguagePack.getString("quit_confirm", langGroup), "Confirm exit", JOptionPane.YES_NO_OPTION);
          		if(selectedValue == 0)
          			System.exit(-1);
		}
		if(e.getActionCommand().equals("load_game")) {
			JFileChooser chooser = new JFileChooser(new File ("./Resources/Saves/"));
			// Note: source for ExampleFileFilter can be found in FileChooserDemo,
			// under the demo/jfc directory in the Java 2 SDK, Standard Edition.
			Cluedo.API.ExampleFileFilter filter = new Cluedo.API.ExampleFileFilter ();
			filter.addExtension("xml");
			filter.setDescription("XML save games");
			chooser.setFileFilter(filter);

			int returnVal = chooser.showOpenDialog(this);
			if(returnVal == JFileChooser.APPROVE_OPTION && chooser.getSelectedFile() != null) {
				try { 
					createRestoreGame(chooser.getSelectedFile());
				}
				catch(Exception ee) {
					JOptionPane.showMessageDialog(this, "Unable to load the save file:\n" + chooser.getSelectedFile(), "Unable to load file.", JOptionPane.INFORMATION_MESSAGE);
				}
			}
			
		}       
		if(e.getActionCommand().equals("new_game")) {
          	System.out.println("Creating new game..");
          	SetupGame setupGame = new SetupGame("New Game..");

			if(setupGame.getInterestingData() != null)
				createNewGame((CluedoConfig)setupGame.getInterestingData());
		}
		else if(e.getActionCommand().equals("options")) {
		    Options o = new Options();
		    o.setVisible(true);
		}
		else if(e.getActionCommand().equals("open_help")) {
		    try {
		        Resources.openDocument(Constants.HTML_ROOT);
		    }
		    catch(Exception exp) {
		        JOptionPane.showMessageDialog(null, "Unable to find help file, make sure you have it installed.", "Error", JOptionPane.INFORMATION_MESSAGE);
		    }
		}	
		
	}

	/**
	 * Sets up the AdvanceGUI component for main game-play
	 * 
	 * @param cluedoConfig gameConfig for new game
	 */
	public void createAdvanceGUI(CluedoConfig cluedoConfig, boolean fromSaveGame) {
	    boolean soundEnabled = true;
	    if(properties.get("sound") != null && properties.get("sound").equals("true")) {
	        soundEnabled = true;
	    }
	    else {
	        soundEnabled = false;
	    }
	    
		guiPointer = new AdvanceGUI("AdvanceGUI GUI 0.1", cluedoConfig, gameController, fromSaveGame, soundEnabled, this);
		showGUI();
	}

	/**
	 * Creates AIs if required, turns them on and shows AdvanceGUI ( main play screen )
	 * 
	 * @param config gameConfig for new game
	 */
	public void createNewGame(CluedoConfig gameConfig) {
		gameController = new GameController();
			
		gameController.setAIs(createAIs(gameConfig));

	//	config.loadCards();
		
		gameConfig.loadMapArea();
			
		createAdvanceGUI(gameConfig, false);
		
		try {
			// Serves no purpose other than to get AI players "ready"
			gameController.directCommand("AIPlayersOn", null);
		}
		catch(Exception error) {
			System.out.println("[GameMenu:localStartNewGame] can't start AI players");
		}

		
		// Set the right game rules
		Vector params = new Vector();
		params.add(new Integer(gameConfig.getGameType()));
		gameController.directCommand("setGameType", params);

		showGUI();	
	}

	public void showGUI() {
		this.setVisible(false);

		guiPointer.setVisible(true);
	}

	/**
	 * Creates a new game based on a previous saved game.
	 * 
	 * @param file file path to xml save file
	 */
	public void createRestoreGame(File file) throws Exception {
		
			String output = "";
			CluedoConfig gameConfig = null;
			String fileName = "";
			
			Vector players = new Vector();
			
			Cluedo.API.GamePersistance gp = new Cluedo.API.GamePersistance();

			fileName = file.getPath();
			System.out.println(fileName);

			boolean fatalException = false;
			
			try { 
				gp.loadGame(fileName);
			}
			catch(java.io.IOException error) {
				System.out.println("Unable to load file.");
				fatalException = true;
			}
			catch (Exception error) {
				error.printStackTrace();
				System.exit(-1);
				System.out.println("Other error.");
			}
			
			if(fatalException == true) {
				throw new Exception();
			}
			
			gameConfig = gp.getGameConfig();
			
			gameConfig.defineCards(gp.getGameCardSet());
			
			gameController = new GameController();
			gameConfig.loadMapArea();
			
			Vector params = new Vector();
			params.add(new Integer(gp.getCurrentPlayer()));
			gameController.directCommand("restorePlayerTurn", params);

			params = new Vector();
			params.add(gp.getEnvelope());
			gameController.directCommand("restoreEnvelopeCards", params);
			
			
			createAIs(gameConfig);

			createAdvanceGUI(gameConfig, true);
			
			try {
				// Serves no purpose other than to get AI players "ready"
				gameController.directCommand("AIPlayersOn", null);
			}
			catch(Exception error) {
				System.out.println("[GameMenu:localStartNewGame] can't start AI players");
			}

			System.out.println("Type passed: "+ gameConfig.getGameType());
			// Set the right game rules
			params = new Vector();
			params.add(new Integer(gameConfig.getGameType()));
			gameController.directCommand("setGameType", params);
			
			
			// Load map areas
			guiPointer.setVisible(true);
		
	}
	
	/**
	 * Creates and starts relevant threads for AI players to be passed to the gameController.
	 * 
	 * @param config gameConfig
	 * 
	 * @return Vector of AI thread pointers.
	 */
	private Vector createAIs(CluedoConfig config) {
		Vector AIs = new Vector();
		
		// configure any AI players and start threads for them
		Player pointer = null;

		Thread aiThread = null;
		for(int i = 0; i < config.getPlayers().size(); i++) {
			pointer = ((Player)config.getPlayers().elementAt(i));

			if(pointer.getPlayerType() >= 1) {
				System.out.println("Found an AI player: " + pointer.getRealName() + " playing as "+ pointer.getCharacter()+".");

				if(pointer.getPlayerType() == 1) {
					
					SimpleAI simpleAI = new SimpleAI("", gameController, pointer.getRealName());
					simpleAI.setMyName(pointer.getRealName());
					AIs.add( simpleAI );
					aiThread = new Thread( simpleAI );
				}
				else if(pointer.getPlayerType() == 2) {
				    SmartSimpleAI ssAi = new SmartSimpleAI("", gameController, pointer.getRealName());
					ComplexAI complexAI = new ComplexAI("", gameController, pointer.getRealName());
					complexAI. setMyName(pointer.getRealName());
					AIs.add( complexAI );
					aiThread = new Thread( complexAI );
				}

				// Start the thread for the AI
				aiThread.start();
			}
		}
			
		return AIs;
	}
	
	
	public static void main(String args[]) {
	    getConfig();
		if(properties.get("decoration") != null && properties.get("decoration").equals("true") ) {
			Cluedo.API.Resources.configureUI();
		}
		if(properties.get("sound") != null && properties.get("sound").equals("true") ) {
		    soundEnabled = true;
		}
		else
		    soundEnabled = false;
		
		GameMenu welcome = new GameMenu("Cluedo");
		
		welcome.setVisible(true);
		
		
	}

	/**
	 * Centre the frame on the screen.
	 *
	 */
	public void centre() {
        	Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        	Dimension frameSize = getSize();
        	frameSize.height = ((frameSize.height > screenSize.height) ? screenSize.height : frameSize.height);
        	frameSize.width = ((frameSize.width > screenSize.width) ? screenSize.width : frameSize.width);
        	setLocation((screenSize.width - frameSize.width) / 2, (screenSize.height - frameSize.height) / 2);
	}

	
	/**
	 * Creates an ImageIcon from a filename, used to show splash window.
	 *  	
	 * @param path path to filename
	 * @param description description for image
	 * 
	 * @return null if unable to load or requested imageIcon
	 */
    protected static ImageIcon createImageIcon(String path,
                                               String description) {
        java.net.URL imgURL = GameMenu.class.getResource(path);
        if (imgURL != null) {
            return new ImageIcon(imgURL, description);
        } else {
            System.err.println("Couldn't find file: " + path);
            return null;
        }
    }    	
    
}